package squares;

import be.kuleuven.cs.som.annotate.Model;
import borders.*;

/**
 * @invar	the temperature of this rock square must be valid
 * 			| isValidTemperature(getTemperature())
 * @invar   the humidity of this square must be valid
 * 			| isValidHumidity(getHumidity())
 * @invar	the borders must be initialized with the 6 directions borders or the hashmap has to be completely empty
 * 			| getBorders().size() == 6
 * 			| for(Direction direction: Direction.values())
 * 			| 	this.getBorderAt(direction) != null
 * 			| 	|| borders.isEmpty()
 * @invar 	The borders of this square are all valid and all walls.
 * 			| for( Direction direction: Direction.values())
 * 			| { this.isValidBorder(direction,this.getBorderAt(direction)) && this.getBorderAt(direction) instanceof Wall
 * @invar	the temperaturestep for the heat damage must be valid.
 * 			| getTemperatureStepHeatDamage() >= 0
 * @version 1.0
 * @author Gilles Groven & Jochen Tombal
 *
 */
public class RockSquare extends Square {
	/**
	 * makes a new rock with a temperature of zero and a humidity of zero, it is also not possible to teleport from this square.
	 * @post
	 * 		the new temperature of this rocksquare is valid
	 * 		| this.isValidTemperature(super.getTemperature(),TemperatureType.CELSIUS)
	 * @post
	 * 		the new humidity of this rocksquare is zero
	 * 		| this.getHumidity() == 0
	 * @post
	 * 		all the borders of this rock square are instanceof Wall and are validBorders
	 * 		| for(Direction direction:Direction.Values())
	 * 		|	this.isValidBorder(direction,this.getBorderAt(direction))
	 * 		|	&&
	 * 		|	this.getBorderAt(direction) instanceof Wall
	 * @post
	 * 		it is not possible to teleport from this RockSquare
	 * 		| this.teleportPossible == false
	 */
	public RockSquare()
	{
		super();
		
	}
	/**
	 * @return	true if the border is a wall and is only connected to this square
	 * 			|result == 	direction != null && 
	 * 			|			border instanceof Wall && 
	 * 			|			border.hasOnlyOneSquareAttached() &&
	 * 			|			(border.getAttachedSquare1().equals(this) || border.getAttachedSquare2().equals(this))
	 */
	@Override
	@Model
	public boolean isValidBorder(Direction direction, Border border)
	{
		if(direction != null)
		{
			if(border instanceof Wall)
			{
				if(border.hasOnlyOneSquareAttached())
				{
					if(border.getAttachedSquare1().equals(this) || border.getAttachedSquare2().equals(this))
					{
						return true;
					}
				}
			}
		}
		return false;
	}
	/**
	 * @return 	true if the border at a given direction is allowed to be changed into a given border which must be a wall
	 * 			|if( border != null && direction != null && border instanceof Wall)
	 * 			| if(Border connected to this)
	 * 			| 	if( !border.hasOnlyOneAttached())
	 * 			|	
	 * 			|		for other attached
	 * 			|			 border != null && direction != null
	 * 			|				then (result == true)
	 * 			|	else
	 * 			| 		then(result == true)
	 * 			|result == false	
	 * 
	 */
	@Override
	public boolean BorderCanBeChanged(Direction direction,Border border)
	{
		if(border == null || direction == null)
		{
			return false;
		}
		if(border.getAttachedSquare1() != null)
		{
			if(!border.getAttachedSquare1().equals(this))
			{
				if(border.getAttachedSquare2() != null)
				{
					if(!border.getAttachedSquare2().equals(this))
					{
						return false;
					}
				}
			}
		}
		if(border instanceof Wall)
		{
			if(!border.hasOnlyOneSquareAttached())
			{
				if(borderInOtherDirection(direction,border.getOtherAttachedSquare(this)))
					return false;
				if((border.getAttachedSquare1().equals(borders.get(direction).getAttachedSquare1()) 
						|| border.getAttachedSquare1().equals(borders.get(direction).getAttachedSquare2()))
						&& (border.getAttachedSquare2().equals(borders.get(direction).getAttachedSquare1()) 
						|| border.getAttachedSquare2().equals(borders.get(direction).getAttachedSquare2())))
				{
					if(isRightDoubleBorderDirection(direction,borders.get(direction).getOtherAttachedSquare(this).getDirectionOfBorder(borders.get(direction))) &&!(border.getOtherAttachedSquare(this) instanceof TransparentSquare))
					{
						return true;
					}
					else
						return false;
				}
				else
					return false;
			}
			else
			{
			if(!borders.get(direction).hasOnlyOneSquareAttached())
				return false;
			else if(borderInOtherDirection(direction,border.getOtherAttachedSquare(this)))
				return false;
			else
				return true;
			}
		}
		else
			return false;
	}
	/**
	 * @post a RockSquare has a humidity of zero percent and 
	 * 		does not interfer with the humidity of other squares
	 * 		|this.humidity = 0
	 */
	@Override
	public void setHumidity(double humidity)
	{
		assert isValidHumidity(humidity);
		assert hasTwoDecimals(humidity);
		this.humidity = 0;
	}
	
	/**
	 * changes the temperature of this rock to the mean of its surrounding (not rock) squares
	 * @post
	 * 		 the temperature of this square is the mean of the surrounding squares or
	 * 		 zero if absent surrounding squares.
	 * 		| new.temperature == this.calculateTemperature()
	 */
	public void adjustTemperature()
	{
		this.temperature = this.calculateTemperature();
	}
	/**
	 * calculates the mean of the temperature of all non rock squares that share a border with this rock
	 * @return
	 * 		the mean of all the temperature of all surrounding non rock squares, if present, all valid temperatures,
	 * 		and therefore is the result also a valid temperature
	 * 		|int i= 0
	 * 		|for( square : surroundingSquares)
	 * 		|	double sum += square.getTemperature
	 * 		|	i++
	 * 		|if(i==0)
	 * 		|	result = 0
	 * 		|result = sum/i
	 * @post result is a valid temperature 
	 * 		this.isValidTemperature(result)
	 */
	@Model
	private double calculateTemperature()
	{
		double temperature = 0;
		int numberOfZeroes = 0;
		for(Direction direction: Direction.values())
		{
			if(borders.get(direction).getOtherAttachedSquare(this) != null && !(borders.get(direction).getOtherAttachedSquare(this) instanceof RockSquare) )
			{
				temperature += borders.get(direction).getOtherAttachedSquare(this).getTemperature();
			}
			else
				numberOfZeroes++;
		}
		if(numberOfZeroes == 6)
		{
		return temperature;
		}
		else
		{
			return temperature/(6-numberOfZeroes);
		}
	}
	@Override
	public void setTeleportationPossible(boolean possible)
	{
	}
	@Override
	public void adjustHumiditySpace()
	{
	}
	@Override
	public void adjustTemperatureSpace()
	{
	}
	@Override
	public void setTemperatureToCelsius(TemperatureType type,double temperature) throws IllegalArgumentException,InvalidTemperatureException, IllegalTemperatureTypeException
	{
	}
	@Override
	public void setTemperature(double temperature) throws InvalidTemperatureException
	{
	}
}
